import { EventClass } from "@lib/alen-helper/node/baseClass";
import { OperatorManager } from "../operators/operatorManager";
import { catchError, concatMap, map, of, filter, Subscription } from "rxjs";

export abstract class BaseController<T extends OperatorManager.OperatorType, ET extends EventClass.EventType> extends EventClass<{
    build: { item: OperatorManager.Item<T> },
    destroy: { item: OperatorManager.Item<T> },
    state: { item: OperatorManager.Item<T> },
} & ET> {
    constructor(
        name: string,
        operatorType: T,
        protected _operatorManager: OperatorManager,
        BaseOptions?: Partial<EventClass.BaseOptions>
    ) {
        super(name, BaseOptions);
        this.operatorType = operatorType;
        this.__subs();
    }
    public readonly operatorType: T;

    private __sub: Subscription | null = null;

    private __unSubs() {
        if (this.__sub) this.__sub.unsubscribe();
        this.__sub = null;
    }

    private __subs() {
        this.__unSubs();
        this.__sub = this._operatorManager.event('build')
            .pipe(filter(e => e.type === this.operatorType))
            .subscribe(e => {
                const item = this.getOperator(e.appid, e.id);
                if (item) this.triggerEvent('build', { item } as any);
            })
        this.__sub.add(
            this._operatorManager.event('destroy')
                .pipe(filter(e => e.type === this.operatorType))
                .subscribe(e => {
                    const item = this.getOperator(e.appid, e.id);
                    if (item) this.triggerEvent('destroy', { item } as any);
                })
        );
        this.__sub.add(
            this._operatorManager.event('state')
                .pipe(filter(e => e.type === this.operatorType))
                .subscribe(e => {
                    const item = this.getOperator(e.appid, e.id);
                    if (item) this.triggerEvent('state', { item } as any);
                })
        );
    }

    getAllOperator(appid: string) {
        return this._operatorManager.find(appid, this.operatorType);
    }

    getOperator(appid: string | null, id: string) {
        const item = this._operatorManager.getItem(appid, id);
        if (!item || item.operator.type !== this.operatorType) return null;
        return item as OperatorManager.Item<T>;
    }

    getState(appid: string, id: string) {
        const item = this.getOperator(appid, id);
        if (!item) return null;
        return item.state;
    }

    start(appid: string, options: string | Partial<OperatorManager.OperatorOptions<T>>) {
        let item: OperatorManager.Item<T>;
        if (typeof options === 'string') {
            const tmp = this.getOperator(appid, options);
            if (!tmp) throw this._err('项目不可用', `找不到 Operator [ ${this.operatorType}]`);
            item = tmp;
        } else {
            item = this._operatorManager.build(appid, this.operatorType, options);
        }
        return this._operatorManager.start(item.appid, item.id)
            .pipe(catchError((err: Error) => of(err)))
            .pipe(concatMap(back => {
                if (back === true) {
                    return of(item.id);
                }
                return this._operatorManager.destroy(item.appid, item.id)
                    .pipe(map(() => {
                        if (back === false) {
                            throw this._err('操作失败');
                        } else {
                            throw back;
                        }
                    }));
            }));
    }

    destroy(appid: string, id: string) {
        return this._operatorManager.destroy(appid, id);
    }
}